/*
 *    Copyright 2022 The DSMS Authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.dsms.modules.mail.service.impl;

import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dsms.common.constant.AlertAppriseTypeEnum;
import com.dsms.common.constant.AlertMessageAppriseStatusEnum;
import com.dsms.modules.alert.entity.AlertApprise;
import com.dsms.modules.alert.entity.AlertContact;
import com.dsms.modules.alert.entity.AlertMessage;
import com.dsms.modules.alert.service.IAlertAppriseService;
import com.dsms.modules.alert.service.IAlertMessageService;
import com.dsms.modules.alert.service.IAlertNotifyHandler;
import com.dsms.modules.mail.model.MailMessage;
import com.dsms.modules.mail.model.convert.MailAccountConvert;
import com.dsms.modules.mail.model.convert.MailMessageConvert;
import com.dsms.modules.mail.service.IMailSendService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;


@Service
@Slf4j
public class MailSendServiceImpl implements IMailSendService, IAlertNotifyHandler {

    private static final String ALERT_TITLE = "Dsms 告警通知";

    /**
     * Mail account map
     */
    private final ConcurrentMap<String, MailAccount> mailAccounts = new ConcurrentHashMap<>();

    @Autowired
    private IAlertAppriseService alertAppriseService;

    @Autowired
    private IAlertMessageService alertMessageService;

    @Override
    @EventListener(ApplicationReadyEvent.class)
    public void initMailAccount() {
        LambdaQueryWrapper<AlertApprise> alertAppriseQuery = Wrappers.lambdaQuery(AlertApprise.class).eq(AlertApprise::getType, AlertAppriseTypeEnum.EMAIL.getCode());
        List<AlertApprise> alertApprises = alertAppriseService.list(alertAppriseQuery);
        if (!alertApprises.isEmpty()) {
            log.info("init email account ...");
            for (AlertApprise alertApprise : alertApprises) {
                updateMailAccount(alertApprise);
            }
        }
    }

    @Override
    public void updateMailAccount(AlertApprise alertApprise) {
        MailAccount mailAccount = MailAccountConvert.convert(alertApprise);
        mailAccounts.put(alertApprise.getSmtpUsername(), mailAccount);
    }


    @Override
    public void sendMail(MailMessage mailMessage) {
        MailAccount mailAccount = mailAccounts.get(mailMessage.getSmtpUsername());
        MailUtil.send(mailAccount, mailMessage.getTos(), mailMessage.getTitle(), mailMessage.getContent(), true, null);
    }


    @Override
    public Integer getType() {
        return AlertAppriseTypeEnum.EMAIL.getCode();
    }

    @Override
    public void sendAlertMessage(AlertApprise apprise, String alertMessage) {
        List<String> contacts = apprise.getContacts().stream().map(AlertContact::getContactAccount).collect(Collectors.toList());
        MailMessage mailMessage = MailMessageConvert.convert(apprise, ALERT_TITLE, alertMessage, contacts);
        sendMail(mailMessage);
    }

    @Override
    public void updateAlertMessageAppriseStatus(AlertMessage alertMessage, boolean isSuccess) {
        //update status only if successfully sent
        if (isSuccess) {
            alertMessage.setEmailStatus(AlertMessageAppriseStatusEnum.UP_AND_APPRISED.getCode());
            LambdaUpdateWrapper<AlertMessage> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(AlertMessage::getId, alertMessage.getId()).set(AlertMessage::getEmailStatus, alertMessage.getEmailStatus());
            alertMessageService.update(updateWrapper);
        }
    }
}
